<?php
/**
 *
 *
 * @author Zeon <scplay@gmail.com>
 * @date 2019/5/28 14:36
 * @copyright PanxSoft Inc.
 */

namespace App\Http\Controllers\App\V1;


use App\Http\Controllers\ApiController;
use App\Http\Requests\App\V1\UserLogin\UserLoginRequest;
use App\Http\Requests\App\V1\UserLogin\UserLoginVerifyCodeRequest;
use App\Models\OpenWechat\WechatUser;
use App\Models\User;
use App\Services\EasySms\EasySmsService;
use App\Services\OAuth\UserThirdPartyService;
use App\Services\Utils\Guard;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Mail;

class UserLoginController extends ApiController
{
    const USER_LOGIN_VERIFY_CODE_CACHE_KEY_PREFIX = 'APP_USER_LOGIN:';
    const VERIFY_CODE_CACHE_SECONDS = 60;

    const ROUTES = [
        'verifyCode'      => 'app.v1.userLogin.verifyCode',
        'emailVerifyCode' => 'app.v1.userLogin.emailVerifyCode',
        'login'           => 'app.v1.userLogin.login',
    ];

    /**
     * 获取登录 / 注册 手机验证码
     *
     * @param UserLoginVerifyCodeRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function verifyCode(UserLoginVerifyCodeRequest $request)
    {
        $area_code = $request->get('area_code');
        $phone = $request->get('phone');
        $verify_code = $this->generateVerifyCode();

        // 为了配合商城的验证需要提供测试的账号，测试用的账号为手机号：18520251102，测试用的验证码为123456
        if($area_code.$phone=='8618520251102')
            $verify_code='123456';

        if (config('pkx.app_user_login_debug')) {
            $debug_code = $verify_code;
        }
        $user_exist = (bool) User::findByAreaCodePhone($area_code, $phone);

        $this->cacheVerifyCode($area_code, $phone, $verify_code);
        $this->sendVerifyCodeSMS($user_exist, $area_code, $phone, $verify_code);

        // ali sms send code
        return $this->response(compact('user_exist', 'debug_code'));
    }

    /**
     * 获取登录 / 注册 邮箱验证码
     *
     * @param UserLoginVerifyCodeRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function emailVerifyCode(UserLoginVerifyCodeRequest $request)
    {
        $email = $request->get('email');

        $verify_code = $this->generateVerifyCode();
        if (config('pkx.app_user_login_debug')) {
            $debug_code = $verify_code;
        }
        $user_exist = (bool) User::findByEmail($email);

        $this->cacheVerifyCodeEmail($email, $verify_code);
        $this->sendVerifyCodeEmail($email, $verify_code);

        // ali sms send code
        return $this->response(compact('user_exist', 'debug_code'));
    }

    /**
     * 用户登录
     *
     * @param UserLoginRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function login(UserLoginRequest $request)
    {
        $email = $request->get('email');

        $phone = $request->get('phone');
        $area_code = $request->get('area_code');

        $password = $request->get('password');
        $verify_code = $request->get('verify_code');

        if ($email && $password) {
            $user = $this->checkGetUserByEmailPassword($email, $password);
        } elseif ($phone && $area_code && $verify_code) {
            $user = $this->checkGetUserByVerifyCode($area_code, $phone, $verify_code);
        } elseif ($phone && $area_code && $password) {
            $user = $this->checkGetUserByPassword($area_code, $phone, $password);
        } else {
            $user = null;
            $this->checkFailed('login credentials missing');
        }

        $token = Guard::JWTUserLogin($user);
        (new UserThirdPartyService)->bindRequestOAuthUser($request, $user);

        $user->load('wechatUser');

        $hathor_mall_api = 'http://hm-api.panxsoft.com/api/v1/app/customer/third-party/hathor-sign';
        $user_json = json_encode($user);
        $post_data = array(
            "user" => $user_json
        );
        $ch = \curl_init();
        \curl_setopt($ch, CURLOPT_URL, $hathor_mall_api);
        \curl_setopt($ch, CURLOPT_POST, 1);
        \curl_setopt($ch, CURLOPT_HEADER, 0);
        // \curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
        \curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        // \curl_setopt($ch,CURLOPT_HTTPHEADER,$header_data);
        \curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = \curl_exec($ch);
        \curl_close($ch);
        $code = json_decode($output)->code;
        $mall_token=0;
        if($code == 0){
            $mall_token=json_decode($output)->jwt_token;
        }
        return $this->response(compact('user', 'token','mall_token'));
    }

    private function verifyCodeCacheKey(string $area_code, string $phone): string
    {
        return self::USER_LOGIN_VERIFY_CODE_CACHE_KEY_PREFIX . $area_code . $phone;
    }

    private function verifyCodeCacheKeyEmail(string $email): string
    {
        return self::USER_LOGIN_VERIFY_CODE_CACHE_KEY_PREFIX . $email;
    }

    /**
     * @param $area_code
     * @param $phone
     * @param string $verify_code
     *
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function cacheVerifyCode(string $area_code,
                                     string $phone,
                                     string $verify_code): void
    {
        $verify_key = $this->verifyCodeCacheKey($area_code, $phone);
            $this->checkUnless(Cache::get($verify_key), trans('service.please_wait_one_min'));

        Cache::put($verify_key, $verify_code, self::VERIFY_CODE_CACHE_SECONDS);
    }

    /**
     * @param string $email
     * @param string $verify_code
     *
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function cacheVerifyCodeEmail(string $email, string $verify_code): void
    {
        $verify_key = $this->verifyCodeCacheKeyEmail($email);
            $this->checkUnless(Cache::get($verify_key), trans('service.please_wait_one_min'));

        Cache::put($verify_key, $verify_code, self::VERIFY_CODE_CACHE_SECONDS);
    }

    /**
     * @param $area_code
     * @param $phone
     * @param $verify_code
     *
     * @return User|\Illuminate\Database\Eloquent\Model|null
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function checkGetUserByVerifyCode(string $area_code,
                                              string $phone,
                                              string $verify_code): User
    {
        $cache_code = Cache::get($this->verifyCodeCacheKey($area_code, $phone));
            $this->checkCanOperate($verify_code === $cache_code, trans('checker.verify_code_error'));

        $user = User::findByAreaCodePhone($area_code, $phone);
        if (! $user) {
            $user = (new User)->create(compact('area_code', 'phone'));
        }

        return $user;
    }

    /**
     * @param $area_code
     * @param $phone
     * @param $password
     *
     * @return User|null
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function checkGetUserByPassword(string $area_code,
                                            string $phone,
                                            string $password): User
    {
        $user = User::findByAreaCodePhone($area_code, $phone);
            $this->checkItemExist($user, trans('checker.password_verify_error'));
            $this->checkIsTrue(password_verify($password, $user->password), trans('checker.password_verify_error'));

        return $user;
    }

    /**
     * @param string $email
     * @param string $password
     *
     * @return User|null
     * @throws \App\Exceptions\ApiAbstractException
     */
    private function checkGetUserByEmailPassword(string $email, string $password): User
    {
        $user = User::findByEmail($email);
            $this->checkItemExist($user, trans('checker.password_verify_error'));
            $this->checkIsTrue(password_verify($password, $user->password), trans('checker.password_verify_error'));

        return $user;
    }

    /**
     * @param bool $user_exist
     * @param string $area_code
     * @param string $phone
     * @param string $verify_code
     *
     * @throws \Exception
     */
    private function sendVerifyCodeSMS(bool $user_exist,
                                       string $area_code,
                                       string $phone,
                                       string $verify_code): void
    {
        if ($user_exist) {
            (new EasySmsService)->loginSend($phone, $verify_code, $area_code);
        } else {
            (new EasySmsService)->registerSend($phone, $verify_code, $area_code);
        }
    }

    /**
     * @param string $email
     * @param string $verify_code
     *
     * @throws \Exception
     */
    private function sendVerifyCodeEmail(string $email, string $verify_code): void
    {
//       Mail::send($e， $verify_code);
    }

    /**
     * @return string
     */
    private function generateVerifyCode(): string
    {
        return (string) rand(100000, 999999);
    }

}